/******************************************************************************* * Copyright (c) 2013 Hani Naguib. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html * * Contributors: * Hani Naguib - initial API and implementation ******************************************************************************/ package com.gvmax.data.queue; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; import java.util.List; import javax.sql.DataSource; import org.apache.commons.lang.StringUtils; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.PreparedStatementCreator; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import com.codahale.metrics.annotation.ExceptionMetered; import com.codahale.metrics.annotation.Timed; import com.gvmax.common.util.Enc; import com.gvmax.common.util.JsonUtils; import com.ryantenney.metrics.annotation.Counted; /** * Implementation of QueueDAO that is JDBC based. * @param <T> Type object in queue */ public class JDBCBasedQueueDAO<T> implements QueueDAO<T> { private Class<?> clazz; private JdbcTemplate jdbcTemplate; private String tableName; private Enc enc; public JDBCBasedQueueDAO(Class<?> clazz, DataSource dataSource, String tableName, String encKey) { this.clazz = clazz; this.jdbcTemplate = new JdbcTemplate(dataSource); this.tableName = tableName; this.enc = new Enc(encKey); } @Override @Counted public String getName() { return tableName; } @Override @Timed @ExceptionMetered public long enqueue(T obj) throws IOException { final String payload = toJson(obj); KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(new PreparedStatementCreator() { @Override public PreparedStatement createPreparedStatement(Connection conn) throws SQLException { PreparedStatement ps = conn.prepareStatement("insert into " + tableName + " ( enqueuedDate, payload ) values (?,?)", new String[] { "id" }); ps.setLong(1, System.currentTimeMillis()); ps.setString(2, payload); return ps; } }, keyHolder); return keyHolder.getKey().longValue(); } @Override @Timed @ExceptionMetered public List<QueueEntry<T>> getEntries(long since, int max) throws IOException { return jdbcTemplate.query("select * from " + tableName + " where id > ? limit " + max, new Object[] { since }, new RowMapper<QueueEntry<T>>() { @Override public QueueEntry<T> mapRow(ResultSet rs, int row) throws SQLException { QueueEntry<T> entry = new QueueEntry<T>(); entry.setId(rs.getLong("id")); entry.setEnqueuedDate(rs.getLong("enqueuedDate")); try { entry.setPayload(fromJson(rs.getString("payload"))); } catch (IOException e) { throw new SQLException(e); } return entry; } }); } @Override @Timed @ExceptionMetered public long size() throws IOException { // TODO: Review deprecated use return jdbcTemplate.queryForLong("select count(id) from " + tableName); } @Override @Timed @ExceptionMetered public int delete(Long... ids) throws IOException { String inIds = StringUtils.join(Arrays.asList(ids), ','); return jdbcTemplate.update("delete from " + tableName + " where id in (" + inIds + ")"); } // ------------------- // JSON // ------------------- private String toJson(T obj) throws IOException { return enc.encrypt(JsonUtils.toJson(obj)); } @SuppressWarnings("unchecked") private T fromJson(String json) throws IOException { return (T) JsonUtils.fromJson(enc.decrypt(json), clazz); } }